Skip to content

Conversation

@Gavin-Rockwood
Copy link

@Gavin-Rockwood Gavin-Rockwood commented Dec 1, 2025

Checklist

Thank you for contributing to QuantumToolbox.jl! Please make sure you have finished the following tasks before opening the PR.

  • Please read Contributing to Quantum Toolbox in Julia.
  • Any code changes were done in a way that does not break public API.
  • Appropriate tests were added and tested locally by running: make test.
  • Any code changes should be julia formatted by running: make format.
  • All documents (in docs/ folder) related to code changes were updated and able to build locally by running: make docs.
  • (If necessary) the CHANGELOG.md should be updated (regarding to the code changes) and built by running: make changelog.

Request for a review after you have completed all the tasks. If you have not finished them all, you can also open a Draft Pull Request to let the others know this on-going work.

Description

Updated TimeEvolutionProblem be parametrically typed using the type of the starting state as well as expanded sesolve, mesolve and mcsolve to allow them to take in operators, superoperators and operators respectively (along with other changes to facilitate this). ssesolve and smesolve are still in progress.

Related issues or PRs

Working on #521

output_func::Union{Tuple,Nothing} = nothing,
kwargs...,
) where {TJC<:LindbladJumpCallbackType}
) where {TJC<:LindbladJumpCallbackType,ST<:Union{Ket,Operator}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
) where {TJC<:LindbladJumpCallbackType,ST<:Union{Ket,Operator}}
) where {ST<:Union{Ket,Operator},TJC<:LindbladJumpCallbackType}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually put this back to just ST<:Union{Ket}. mcsolve returns the average density matrices of all trajectories. Extra work would need to be done to expand _average_traj_states to take a matrix of operators, turn each column into kets and then averaging the density matrix for each of those kets for all trajectories. I don't think this would be hard to do but I'm not sure how useful it would be?

ensemble_prob = TimeEvolutionProblem(
EnsembleProblem(prob_mc.prob, prob_func = _prob_func, output_func = _output_func[1], safetycopy = false),
prob_mc.times,
ST(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ST(),
ψ0.type,

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was replaced with prob_mc.states_type.

normalize_states::Union{Val,Bool} = Val(true),
kwargs...,
) where {TJC<:LindbladJumpCallbackType}
) where {TJC<:LindbladJumpCallbackType} where {ST<:Union{Ket,Operator}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
) where {TJC<:LindbladJumpCallbackType} where {ST<:Union{Ket,Operator}}
) where {ST<:Union{Ket,Operator},TJC<:LindbladJumpCallbackType}

ens_prob = TimeEvolutionProblem(
EnsembleProblem(prob.prob, prob_func = _prob_func, output_func = _output_func[1], safetycopy = false),
prob.times,
StateOpType(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
StateOpType(),
prob.state_type,

prob = ODEProblem{getVal(inplace),FullSpecialize}(U, ψ0, tspan, params; kwargs4...)

return TimeEvolutionProblem(prob, tlist, H_evo.dimensions)
return TimeEvolutionProblem(prob, tlist, ST(), H_evo.dimensions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return TimeEvolutionProblem(prob, tlist, ST(), H_evo.dimensions)
return TimeEvolutionProblem(prob, tlist, ψ0.type, H_evo.dimensions)

Copy link
Author

@Gavin-Rockwood Gavin-Rockwood Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed because psi0 gets overwritten in line 82 and is no longer a quantum object in line 93. I can leave like this or I can put a line states_type = ѱ0.data somewhere before 82.

Edit: actually that is exactly what I did for mesolve so I will do the same for sesolve and elsewhere.

)

return TimeEvolutionProblem(prob, tlist, dims, (isoperket = Val(isoperket(ψ0)),))
return TimeEvolutionProblem(prob, tlist,StateOpType(), dims, ())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return TimeEvolutionProblem(prob, tlist,StateOpType(), dims, ())
return TimeEvolutionProblem(prob, tlist,ψ0.type, dims)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to mesolve, I introduced a states_type variable that is defined during the definition of $\rho 0$.

ensemble_prob = TimeEvolutionProblem(
EnsembleProblem(prob_sme, prob_func = _prob_func, output_func = _output_func[1], safetycopy = true),
prob_sme.times,
StateOpType(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
StateOpType(),
ψ0.type,

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was replaced with prob_sme.states_type.

)

return TimeEvolutionProblem(prob, tlist, dims)
return TimeEvolutionProblem(prob, tlist, ST(), dims)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return TimeEvolutionProblem(prob, tlist, ST(), dims)
return TimeEvolutionProblem(prob, tlist, ψ0.type, dims)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to sesolve, this got updated to a states_type variable defined near the top of the function.

ensemble_prob = TimeEvolutionProblem(
EnsembleProblem(prob_sme, prob_func = _prob_func, output_func = _output_func[1], safetycopy = true),
prob_sme.times,
ST(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ST(),
ψ0.type,

Copy link
Author

@Gavin-Rockwood Gavin-Rockwood Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This became prob_sme.times. (actually prob_sse, I changed it to be consistent). Though, as of right now, the only type ssesolve will take is just Ket. The there is some issue with how the problem is defined that makes it so it cannot take in matrices. Same also didn't update smesolve for the same reason.

Comment on lines 109 to 127
T = Base.promote_eltype(L_evo, ψ0)
ρ0 = if isoperket(ψ0) # Convert it to dense vector with complex element type
to_dense(_complex_float_type(T), copy(ψ0.data))
else
to_dense(_complex_float_type(T), mat2vec(ket2dm(ψ0).data))
# ρ0 = if isoperket(ψ0) # Convert it to dense vector with complex element type
# to_dense(_complex_float_type(T), copy(ψ0.data))
# else
# to_dense(_complex_float_type(T), mat2vec(ket2dm(ψ0).data))
# end
if isoper(ψ0)
ρ0 = to_dense(_complex_float_type(T), mat2vec(ψ0.data))
state_type = Operator()
elseif isoperket(ψ0)
ρ0 = to_dense(_complex_float_type(T), copy(ψ0.data))
state_type = OperatorKet()
elseif isket(ψ0)
ρ0 = to_dense(_complex_float_type(T), mat2vec(ket2dm(ψ0).data))
state_type = Operator()
elseif issuper(ψ0)
ρ0 = to_dense(_complex_float_type(T), copy(ψ0.data))
state_type = SuperOperator()
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
T = Base.promote_eltype(L_evo, ψ0)
ρ0 = if isoperket(ψ0) # Convert it to dense vector with complex element type
to_dense(_complex_float_type(T), copy(ψ0.data))
else
to_dense(_complex_float_type(T), mat2vec(ket2dm(ψ0).data))
# ρ0 = if isoperket(ψ0) # Convert it to dense vector with complex element type
# to_dense(_complex_float_type(T), copy(ψ0.data))
# else
# to_dense(_complex_float_type(T), mat2vec(ket2dm(ψ0).data))
# end
if isoper(ψ0)
ρ0 = to_dense(_complex_float_type(T), mat2vec(ψ0.data))
state_type = Operator()
elseif isoperket(ψ0)
ρ0 = to_dense(_complex_float_type(T), copy(ψ0.data))
state_type = OperatorKet()
elseif isket(ψ0)
ρ0 = to_dense(_complex_float_type(T), mat2vec(ket2dm(ψ0).data))
state_type = Operator()
elseif issuper(ψ0)
ρ0 = to_dense(_complex_float_type(T), copy(ψ0.data))
state_type = SuperOperator()
end
# Convert to dense vector with complex element type
T = _complex_float_type(Base.promote_eltype(L_evo, ψ0))
if isoperket(ψ0) || issuper(ψ0)
ρ0 = to_dense(T, copy(ψ0.data))
states_type = ψ0.type
else
ρ0 = to_dense(T, mat2vec(ket2dm(ψ0).data))
states_type = Operator()
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ket2dm will do nothing if the input is density matrix (Operator), so it doesn't hurt performance, and we can also do ket2dm for Operator input.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, maybe also use states_type instead of state_type to avoid confusion, since we call it states_type in TimeEvolutionProblem

Comment on lines +332 to 340
if isoper(state)
to_dense(_complex_float_type(T), mat2vec(state.data))
elseif isoperket(state)
to_dense(_complex_float_type(T), copy(state.data))
elseif isket(state)
to_dense(_complex_float_type(T), mat2vec(ket2dm(state).data))
elseif issuper(state)
to_dense(_complex_float_type(T), copy(state.data))
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Suggested change
if isoper(state)
to_dense(_complex_float_type(T), mat2vec(state.data))
elseif isoperket(state)
to_dense(_complex_float_type(T), copy(state.data))
elseif isket(state)
to_dense(_complex_float_type(T), mat2vec(ket2dm(state).data))
elseif issuper(state)
to_dense(_complex_float_type(T), copy(state.data))
end
if isoperket(state) || issuper(state)
to_dense(T, copy(state.data))
else
to_dense(T, mat2vec(ket2dm(state).data))
end

if getVal(isoperket)
ρt = map-> QuantumObject(ϕ, type = OperatorKet(), dims = dimensions), sol.u)
function _gen_mesolve_solution(sol, prob::TimeEvolutionProblem{ST}) where {ST<:Union{Operator,OperatorKet,SuperOperator}}
if prob.states_type == Operator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here should be

Suggested change
if prob.states_type == Operator
if prob.states_type isa Operator

cause prob.states_type should be Operator() ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants